﻿Imports Microsoft.VisualBasic
Imports Microsoft.Practices.EnterpriseLibrary.Logging
Imports System.Xml

Public Class XMLFile
    Const Category As String = "XMLFile"

    ''' <summary>
    ''' Check whether password is correct
    ''' </summary>
    ''' <param name="username"></param>
    ''' <param name="password"></param>
    ''' <returns>Empty string if password is correct, otherwise returns the error message</returns>
    ''' <remarks></remarks>
    Public Shared Function CheckPassword(ByVal username As String, ByVal password As String) As String
        Dim Hash As String = General.EncryptStringToHash(password)
        Dim UserDoc As XmlDocument = GetUserFile()
        If UserDoc Is Nothing Then
            CheckPassword = "Userfile '" & ConfigurationManager.AppSettings("UserFile").ToString & "' not found. " & _
                         "Could not check password."
        Else
            Dim Node As XmlNode = UserDoc.SelectSingleNode("/users/user[@email=""" & username & """]")
            If Node Is Nothing Then
                CheckPassword= "Username '" & username & "' not found in Usersfile."
            Else
                Dim StoredHash As String = Node.Attributes("hash").Value.ToString
                If StoredHash = Hash Then
                    CheckPassword = String.Empty
                Else
                    'Special case: If stored hash is empty, no password needs to be supplied
                    If password = String.Empty And StoredHash = String.Empty Then
                        CheckPassword = String.Empty
                    Else
                        CheckPassword = "Password incorrect for user '" & username & "'."
                    End If
                End If
            End If
        End If
    End Function

    ''' <summary>
    ''' Save new password Hash to User File XML Document
    ''' </summary>
    ''' <param name="username"></param>
    ''' <param name="passwordHash"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function SavePassword(ByVal username As String, ByVal passwordHash As String) As String
        Dim UserDoc As XmlDocument = GetUserFile()
        If UserDoc Is Nothing Then
            SavePassword = "Userfile '" & ConfigurationManager.AppSettings("UserFile").ToString & "' not found. " & _
                         "Could not check password."
        Else
            Dim Node As XmlNode = UserDoc.SelectSingleNode("/users/user[@email=""" & username & """]")
            If Node Is Nothing Then
                SavePassword = "Username '" & username & "' not found in Usersfile."
            Else
                Node.Attributes("hash").Value = passwordHash
                UserDoc.Save(ConfigurationManager.AppSettings("UserFile").ToString)
                SavePassword = String.Empty
            End If
        End If
    End Function

    ''' <summary>
    ''' Get XML Document
    ''' </summary>
    ''' <param name="filename">Full Filepath</param>
    ''' <returns>XMLDoc or nothing</returns>
    ''' <remarks></remarks>
    Public Shared Function GetXMLDocument(ByVal filename As String) As XmlDocument
        Const LogTitle As String = "GetXMLDocument"
        If System.IO.File.Exists(filename) Then
            Dim doc As XmlDocument = New XmlDocument()
            doc.Load(filename)
            Return doc
        Else
            Logger.Write("File does not exist: '" & filename & "'.", Category, 200, 0, Diagnostics.TraceEventType.Warning, LogTitle)
            Return Nothing
        End If
    End Function

    ''' <summary>
    ''' Gets value of give node
    ''' </summary>
    ''' <param name="xmlDoc">Document to be checked</param>
    ''' <param name="nodeName">Name of the node which values should be returned</param>
    ''' <returns>Value of the node. If node is nothing returns empty string</returns>
    ''' <remarks></remarks>
    Public Shared Function GetXMLNodeValue(ByVal xmlDoc As XmlDocument, ByVal nodeName As String) As String
        Dim ChildNode As XmlNode
        If xmlDoc Is Nothing Then
            Return ""
        Else
            ChildNode = xmlDoc.SelectSingleNode(nodeName)
            If ChildNode Is Nothing Then
                Return ""
            Else
                Return ChildNode.InnerText
            End If
        End If
    End Function

    ''' <summary>
    ''' Retrieve XMLDoc containing all user information
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function GetUserFile() As XmlDocument
        Return GetXMLDocument(ConfigurationManager.AppSettings("UserFile").ToString)
    End Function


    ''' <summary>
    ''' Refresh completed percentage
    ''' </summary>
    ''' <param name="project">(Directory) name of the current project</param>
    ''' <param name="language">shortcut of language, e.g. de</param>
    ''' <param name="filename">File which was updated, e.g. beta.aspx. Or nothing to check all files</param>
    ''' <param name="logProperties"></param>
    ''' <remarks></remarks>
    Public Shared Sub ComputePercentage(ByVal project As String, ByVal language As String, _
                                        ByVal filename As String, ByVal logProperties As Dictionary(Of String, Object))
        Const LogTitle As String = "ComputePercentage"
        Dim LanguageXML As System.Xml.XmlDocument
        Logger.Write(LogTitle & " -> Start [" & project & " - " & language & " - " & filename & "]", Category, 10, 0, Diagnostics.TraceEventType.Start, LogTitle, logProperties)
        Dim Directory As String = ConfigurationManager.AppSettings("ProjectDirectory").ToString & project & "\"
        If Not IO.File.Exists(Directory & language & ".xml") Then
            Logger.Write("Language file '" & Directory & language & ".xml' does not exist.", Category, 100, 0, Diagnostics.TraceEventType.Information, LogTitle, logProperties)
            'Create new language file
            'Now write the main chart xml for Form Update
            Dim writer As New XmlTextWriter(Directory & language & ".xml", System.Text.Encoding.UTF8)
            Logger.Write("Creating '" & Directory & language & ".xml", Category, 10, 0, Diagnostics.TraceEventType.Verbose, LogTitle, logProperties)
            With writer
                .Formatting = Formatting.Indented
                .Indentation = 3
                .WriteStartDocument()
                .WriteComment("Created on " & Now.ToString)
                .WriteStartElement("files")
                .WriteAttributeString("language", language)

                Dim ResXFile, ShortName As String
                For Each ResXFile In IO.Directory.GetFiles(Directory, "*.resx", IO.SearchOption.TopDirectoryOnly)
                    .WriteStartElement("file")
                    ShortName = Replace(Mid$(ResXFile, Len(Directory) + 1), ".resx", "")
                    Logger.Write("Adding '" & ShortName & "'.", Category, 10, 0, Diagnostics.TraceEventType.Verbose, LogTitle, logProperties)
                    .WriteElementString("name", ShortName)
                    .WriteElementString("percentcompleted", 0)
                    .WriteElementString("lastchange", Now.ToShortDateString)
                    .WriteEndElement() '</file>
                Next

                .WriteEndElement() '</files>
                Logger.Write("All files added.", Category, 10, 0, Diagnostics.TraceEventType.Verbose, LogTitle, logProperties)
                .WriteEndDocument()
                .Close()
                Logger.Write("Created '" & Directory & language & ".xml successfully.", Category, 100, 0, Diagnostics.TraceEventType.Information, LogTitle, logProperties)
            End With
        End If
        LanguageXML = XMLFile.GetXMLDocument(Directory & language & ".xml")
        Dim AllFiles As System.Xml.XmlNodeList = LanguageXML.SelectNodes("/files/file")
        Logger.Write("Language File '" & Directory & language & ".xml' contains " & AllFiles.Count & _
                     " Resource files.", Category, 10, 0, Diagnostics.TraceEventType.Verbose, LogTitle, logProperties)
        Dim SingleFile, EnglishNode, TranslatedNode As System.Xml.XmlNode
        Dim Skip As Boolean
        Dim EnglishDoc, TranslatedDoc As System.Xml.XmlDocument
        Dim CurrentFile, NodeName As String
        Dim SummaryUpdated As Boolean = False
        Dim FileElements, TranslatedFileElements, Percentage As Integer
        If Not IO.Directory.Exists(Directory & language) Then
            Logger.Write("Creating new directory '" & Directory & language & "' now.", Category, 10, 0, Diagnostics.TraceEventType.Verbose, LogTitle, logProperties)
            IO.Directory.CreateDirectory(Directory & language)
        End If
        For Each SingleFile In AllFiles
            CurrentFile = SingleFile.SelectSingleNode("name").InnerText
            If (filename Is Nothing) Then
                Skip = False
            ElseIf (CurrentFile = filename) Then
                Skip = False
            Else
                Skip = True
            End If
            If Skip Then
                Logger.Write("Skip '" & CurrentFile & "'.", Category, 10, 0, Diagnostics.TraceEventType.Verbose, LogTitle, logProperties)
            Else
                Logger.Write("Checking '" & CurrentFile & "'.", Category, 10, 0, Diagnostics.TraceEventType.Verbose, LogTitle, logProperties)
                EnglishDoc = XMLFile.GetXMLDocument(Directory & CurrentFile & ".resx")
                If EnglishDoc Is Nothing Then
                    Logger.Write("Could not find '" & Directory & CurrentFile & ".resx'!", Category, 200, 0, Diagnostics.TraceEventType.Warning, LogTitle, logProperties)
                Else
                    TranslatedDoc = XMLFile.GetXMLDocument(Directory & language & "\" & CurrentFile & "." & language & ".resx")
                    If TranslatedDoc Is Nothing Then
                        Logger.Write("Could not find '" & Directory & language & "\" & CurrentFile & "." & language & ".resx'!", Category, 10, 0, Diagnostics.TraceEventType.Verbose, LogTitle, logProperties)
                        'Create empty translation file
                        Dim Node As System.Xml.XmlNode
                        For Each Node In EnglishDoc.SelectNodes("/root/data/value")
                            Node.InnerText = String.Empty
                        Next
                        EnglishDoc.Save(Directory & language & "\" & CurrentFile & "." & language & ".resx")
                        Logger.Write("Saved empty '" & Directory & language & "\" & CurrentFile & "." & language & ".resx'.", Category, 10, 0, Diagnostics.TraceEventType.Verbose, LogTitle, logProperties)
                        SingleFile.SelectSingleNode("percentcompleted").InnerText = 0
                    Else
                        FileElements = 0
                        TranslatedFileElements = 0
                        For Each EnglishNode In EnglishDoc.SelectNodes("root/data")
                            FileElements += 1
                            NodeName = EnglishNode.Attributes("name").InnerXml
                            TranslatedNode = TranslatedDoc.SelectSingleNode("root/data[@name='" & NodeName & "']")
                            If TranslatedNode Is Nothing Then
                                Logger.Write("Item '" & NodeName & "' is missing.", Category, 10, 0, Diagnostics.TraceEventType.Verbose, LogTitle, logProperties)
                            Else
                                TranslatedNode = TranslatedNode.SelectSingleNode("value")
                                If TranslatedNode Is Nothing Then
                                    Logger.Write("Item '" & NodeName & "' has no node 'value'.", Category, 10, 0, Diagnostics.TraceEventType.Verbose, LogTitle, logProperties)
                                Else
                                    If Trim(TranslatedNode.InnerText).Length > 0 Then
                                        TranslatedFileElements += 1
                                    Else
                                        Logger.Write("Existing node '" & NodeName & "' is not yet translated (value is empty).", Category, 10, 0, Diagnostics.TraceEventType.Verbose, LogTitle, logProperties)
                                    End If
                                End If
                            End If
                        Next
                        If FileElements = TranslatedFileElements Then
                            Logger.Write("File '" & filename & "' translated successfully to '" & language & "'.", Category, 10, 0, Diagnostics.TraceEventType.Verbose, LogTitle, logProperties)
                        Else
                            Logger.Write(TranslatedFileElements.ToString & " of " & FileElements.ToString & " elements in file '" & _
                                         filename & "' translated to '" & language & "'.", Category, 10, 0, Diagnostics.TraceEventType.Verbose, LogTitle, logProperties)
                        End If
                        If FileElements = 0 Then
                            Percentage = 100
                        Else
                            Percentage = CInt(TranslatedFileElements / FileElements * 100)
                        End If
                        Logger.Write("Percent completed: " & Percentage.ToString & " %.", Category, 10, 0, Diagnostics.TraceEventType.Verbose, LogTitle, logProperties)
                        'TotalElements += FileElements
                        'TranslatedElements += TranslatedFileElements
                    End If
                End If
                'Check whether percentage is changed
                If CInt(SingleFile.SelectSingleNode("percentcompleted").InnerText) = Percentage Then
                    Logger.Write("Completed percentage (" & Percentage.ToString & "%) is already stored correct.", Category, 10, 0, Diagnostics.TraceEventType.Verbose, LogTitle, logProperties)
                Else
                    Logger.Write("Update currently stored percentage (" & SingleFile.SelectSingleNode("percentcompleted").InnerText & _
                                 " %).", Category, 10, 0, Diagnostics.TraceEventType.Verbose, LogTitle, logProperties)
                    SingleFile.SelectSingleNode("percentcompleted").InnerText = Percentage
                    SingleFile.SelectSingleNode("lastchange").InnerText = Now.ToString
                    If Not SummaryUpdated Then
                        SummaryUpdated = True
                    End If

                End If
            End If
        Next
        If Not SummaryUpdated Then
            Logger.Write("No percentage was updated. No need to save xml.", Category, 10, 0, Diagnostics.TraceEventType.Verbose, LogTitle, logProperties)
        Else
            Logger.Write("Percentage was changed. Saving configuration file.", Category, 10, 0, Diagnostics.TraceEventType.Verbose, LogTitle, logProperties)
            LanguageXML.Save(Directory & language & ".xml")
            Logger.Write(Directory & language & ".xml updated.", Category, 10, 0, Diagnostics.TraceEventType.Verbose, LogTitle, logProperties)
        End If
        Logger.Write(LogTitle & " -> End.", Category, 10, 0, Diagnostics.TraceEventType.Stop, LogTitle, logProperties)
    End Sub

    ''' <summary>
    ''' Compute a summary for given project containing languages and percentages
    ''' </summary>
    ''' <param name="project">name of the project to be checked</param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function ComputeSummary(ByVal project As String) As System.Data.DataTable
        Const LogTitle As String = "ComputeSummary"
        Dim LogProperties As New Dictionary(Of String, Object)
        LogProperties = General.CreateLogProperties("Anonymous")

        Logger.Write(LogTitle & " -> Start [" & project & "]", Category, 10, 0, Diagnostics.TraceEventType.Start, LogTitle, logProperties)
        Dim Directory As String = ConfigurationManager.AppSettings("ProjectDirectory").ToString & project & "\"
        If Not IO.Directory.Exists(Directory) Then
            Logger.Write("Directory '" & Directory & "' does not exist.", Category, 100, 0, Diagnostics.TraceEventType.Information, LogTitle, LogProperties)
            ComputeSummary = Nothing
        Else
            Logger.Write("Directory '" & Directory & "' exists.", Category, 10, 0, Diagnostics.TraceEventType.Verbose, LogTitle, LogProperties)
            Dim AllLanguageFiles As String()
            Dim LanguageFilename As String
            Dim LanguageXML As System.Xml.XmlDocument
            AllLanguageFiles = IO.Directory.GetFiles(Directory, "*.xml", IO.SearchOption.TopDirectoryOnly)
            Logger.Write("Directory '" & Directory & "' contains " & AllLanguageFiles.Count.ToString & " xml-files.", Category, 10, 0, Diagnostics.TraceEventType.Verbose, LogTitle, LogProperties)
            Dim DT As New Data.DataTable("Summary")
            With DT.Columns
                .Add("LanguageCode", GetType(String))
                .Add("Percentage", GetType(Int32))
                .Add("LastUpdate", GetType(Date))
            End With
            Dim Row As Data.DataRow
            Dim Percentage As Integer
            Dim LastUpdate As DateTime
            Dim LastChange As DateTime
            Dim Node As System.Xml.XmlNode

            For Each LanguageFilename In AllLanguageFiles
                LanguageXML = XMLFile.GetXMLDocument(LanguageFilename)
                Row = DT.NewRow
                Row.Item("LanguageCode") = LanguageXML.SelectSingleNode("files").Attributes("language").Value
                Percentage = 0
                LastUpdate = DateTime.MinValue
                For Each Node In LanguageXML.SelectNodes("/files/file")
                    Percentage += CInt(Node.Item("percentcompleted").InnerText)
                    If IsDate(Node.Item("lastchange").InnerText) Then
                        LastChange = Convert.ToDateTime(Node.Item("lastchange").InnerText)
                        If LastChange > LastUpdate Then
                            LastUpdate = LastChange
                        End If
                    End If
                Next
                Percentage = Percentage / LanguageXML.SelectNodes("/files/file").Count
                Row.Item("Percentage") = Percentage
                Row.Item("LastUpdate") = LastUpdate
                DT.Rows.Add(Row)
            Next
            ComputeSummary = DT
        End If
    End Function
End Class